﻿using CSRedis;
using ThresholdAssistant.Redis.Constants;
using ThresholdAssistant.Tools;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ThresholdAssistant.Redis
{
    /// <summary>
    /// Redis客户端
    /// </summary>
    public class RedisClientUtil
    {
        /// <summary>
        /// CsRedis客户端
        /// </summary>
        private CSRedisClient client;

        /// <summary>
        ///全局随机数-用于QPS大的时候，随机加上失效的秒数，防止redis在一瞬间失效，防止雪崩前提
        /// </summary>
        private static readonly Random random = new Random();

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public RedisClientUtil()
        {
            client = RedisClientProvider.GetRedisClient();
        }

        /// <summary>
        /// 指定配置名称
        /// </summary>
        /// <param name="connectionName"></param>
        public RedisClientUtil(string connectionName)
        {
            client = RedisClientProvider.GetRedisClient(connectionName);
        }

        /// <summary>
        /// 获取随机的过期时间
        /// </summary>
        /// <param name="minTimeoutSeconds">最小的超时时间(单位：秒)</param>
        /// <param name="maxTimeoutSeconds">最大的超时时间(单位：秒)</param>
        /// <returns></returns>
        public int RandomExpired(int minTimeoutSeconds, int maxTimeoutSeconds) => random.Next(minTimeoutSeconds, maxTimeoutSeconds);

        #region 同步操作
        /// <summary>
        /// 检查缓存Key是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(string key) => client.Exists(key);

        /// <summary>
        /// 批量删除缓存Key
        /// </summary>
        /// <param name="key"></param>
        /// <returns>删除成功的记录数量</returns>
        public bool DeleteKey(string key) => client.Del(key) > 0;

        /// <summary>
        /// 批量删除缓存Key
        /// </summary>
        /// <param name="keys">key列表</param>
        /// <returns>删除成功的记录数量</returns>
        public bool DeleteKey(params string[] keys) => client.Del(keys) > 0;

        /// <summary>
        /// 重新命名key
        /// </summary>
        /// <param name="key">就的redis key</param>
        /// <param name="newKey">新的redis key</param>
        /// <returns></returns>
        public bool RenameKey(string key, string newKey) => client.Rename(key, newKey);

        /// <summary>
        /// 设置缓存过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeoutSeconds"></param>
        public bool SetExpire(string key, int timeoutSeconds) => client.Expire(key, timeoutSeconds);

        /// <summary>
        /// 获取String类型的缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string StringGet(string key) => client.Get(key);

        /// <summary>
        /// 获取String类型的缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T StringGet<T>(string key)
        {
            T result = default;
            try
            {
                byte[] btyes = client.Get<byte[]>(key);
                result = ProtoBufConvert.DeserializeObject<T>(btyes);
            }
            catch (Exception)
            {
                if (result == null && result.IsBaseType())
                {
                    return client.Get<T>(key);
                }
            }
            return result;

        }

        /// <summary>
        /// 设置String类型缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireSeconds"></param>
        /// <returns></returns>
        public bool StringSet<T>(string key, T value, int expireSeconds = 604800)
        {
            bool isSuccess = false;
            try
            {
                byte[] bytes = ProtoBufConvert.SerializeObject(value);
                isSuccess = client.Set(key, bytes, expireSeconds);
            }
            catch (Exception)
            {

            }
            return isSuccess;
        }

        /// <summary>
        /// 设置String类型缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireSeconds"></param>
        /// <returns></returns>
        public bool StringSet(string key, string value, int expireSeconds = 604800) => client.Set(key, value, expireSeconds);

        /// <summary>
        /// 原子性递增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <param name="expireSeconds">缓存过期时间(单位：秒)</param>
        /// <returns>增长后的值</returns>
        public long StringIncrement(string key, long value = 1, int expireSeconds = 604800)
        {
            var newValue = client.IncrBy(key, value);
            SetExpire(key, expireSeconds);
            return newValue;
        }

        /// <summary>
        /// 原子性递增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <returns>增长后的值</returns>
        public long StringIncrementNoExpire(string key, long value = 604800)
        {
            return client.IncrBy(key, value);
        }

        /// <summary>
        /// 原子性递增 绝对过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <param name="expireSeconds">过期时间</param>
        /// <returns>增长后的值</returns>
        public long StringIncrementByAbsoluteExpire(string key, long value = 1, int expireSeconds = 604800)
        {
            var newValue = client.IncrBy(key, value);
            if (newValue == value)
            {
                SetExpire(key, expireSeconds);
            }
            return newValue;
        }

        /// <summary>
        /// 分布式锁
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeoutSeconds">缓存时间(单位：秒)</param>
        /// <param name="autoDelay">是否自动延迟</param>
        /// <returns></returns>
        public CSRedisClientLock Lockup(string key, int timeoutSeconds = 604800, bool autoDelay = true) => client.Lock(key, timeoutSeconds, autoDelay);

        /// <summary>
        /// 检查hash键是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public bool ContainsHashKey(string key, string hashField) => client.HExists(key, hashField);

        /// <summary>
        /// 获取hash表的字段数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public long GetHashCount(string key) => client.HLen(key);

        /// <summary>
        /// 移除hash中的某值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public bool DeleteHash(string key, string hashField) => client.HDel(key, hashField) > 0;

        /// <summary>
        /// 移除hash中的某值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="hashFields"></param>
        /// <returns></returns>
        public long DeleteHash(string key, params string[] hashFields) => client.HDel(key, hashFields);

        /// <summary>
        /// 获取Hash值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public string HashGet(string key, string hashField) => client.HGet(key, hashField);

        /// <summary>
        /// 获取Hash值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public T HashGet<T>(string key, string hashField)
        {
            T result = default;
            try
            {
                byte[] bytes = client.HGet<byte[]>(key, hashField);
                result = ProtoBufConvert.DeserializeObject<T>(bytes);
            }
            catch (Exception)
            {
                if (result == null && result.IsBaseType())
                {
                    result = client.HGet<T>(key, hashField);
                }
            }
            return result;
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public bool HashSet(string key, string hashField, string value, int timeoutSeconds = 604800)
        {
            return Eval<bool>(LuaScriptConstant.HsetExpireScript, key, hashField, value, timeoutSeconds);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public bool HashSet<T>(string key, string hashField, T value, int timeoutSeconds = 604800) where T : class
        {
            byte[] bytes = ProtoBufConvert.SerializeObject(value);
            return Eval<bool>(LuaScriptConstant.HsetExpireScript, key, hashField, bytes, timeoutSeconds);
        }

        /// <summary>
        /// 原子性递增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <param name="timeoutSeconds">缓存过期时间（单位：秒）</param>
        /// <returns>增长后的值</returns>
        public long HashIncrement(string key, string hashField, long value = 1, int timeoutSeconds = 604800)
        {
            long increment = 0;
            try
            {
                bool keyExists = ContainsKey(key);//缓存是否存在
                increment = client.HIncrBy(key, hashField, value);
                if (!keyExists)
                {
                    SetExpire(key, timeoutSeconds);
                }
            }
            catch
            {
            }
            return increment;
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeoutSeconds"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool SetNx(string key, object value, int timeoutSeconds)
        {
            bool isSuccess = false;
            try
            {
                return Eval<bool>(LuaScriptConstant.SetNxScript, key, value, timeoutSeconds);
            }
            catch (Exception)
            {
                DeleteKey(key);
            }
            return isSuccess;
        }

        /// <summary>
        /// 分布式锁
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public CSRedisClientLockNx LockNx(string key, int timeoutSeconds = 5)
        {
            CSRedisClientLockNx lockClient = null;
            try
            {
                bool isSuccess = SetNx(key, 1, timeoutSeconds);
                if (isSuccess)
                {
                    //创建客户端
                    lockClient = new CSRedisClientLockNx(key, client);
                }
            }
            catch (Exception)
            {
                DeleteKey(key);
            }
            return lockClient;
        }

        /// <summary>
        /// 消息发布
        /// </summary>
        /// <param name="channel">频道名</param>
        /// <param name="message">消息内容</param>
        /// <returns></returns>
        public long PublishNoneMessageId(string channel, string message)
        {
            return client.PublishNoneMessageId(channel, message);
        }

        /// <summary>
        /// 将一个或多个值插入到列表头部
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value">一个或多个值</param>
        /// <returns>执行 LPUSH 命令后，列表的长度</returns>
        public long LPush<T>(string key, params T[] value) where T : class
        {
            if (value != null && value.Length > 0)
            {
                return client.LPush(key, value);
            }
            return 0L;
        }

        /// <summary>
        /// 对一个列表进行修剪，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="start"> 开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public bool LTrim<T>(string key, long start, long stop) where T : class
        {
            return client.LTrim(key, start, stop);
        }

        /// <summary>
        /// 移出并获取列表的第一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string LPop(string key)
        {
            return client.LPop(key);
        }

        /// <summary>
        /// 移出并获取列表的第一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T LPop<T>(string key) where T : class
        {
            return client.LPop<T>(key);
        }

        /// <summary>
        /// 移出并获取列表的最后一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string RPop(string key)
        {
            return client.RPop(key);
        }

        /// <summary>
        /// 移出并获取列表的最后一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T RPop<T>(string key) where T : class
        {
            return client.RPop<T>(key);
        }

        /// <summary>
        /// 获取列表长度
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public long LLen(string key)
        {
            return client.LLen(key);
        }

        /// <summary>
        /// 获取列表指定范围内的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop"> 结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public string[] LRange(string key, long start, long stop)
        {
            return client.LRange(key, start, stop);
        }

        /// <summary>
        /// 获取列表指定范围内的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop"> 结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public T[] LRange<T>(string key, long start, long stop) where T : class
        {
            return client.LRange<T>(key, start, stop);
        }

        /// <summary>
        /// 订阅Redis
        /// </summary>
        /// <param name="key"></param>
        /// <param name="action"></param>
        public void Subscribe(string key, Action<string> action) => client.Subscribe((key, msg => action(msg.Body)));

        /// <summary>
        /// 订阅Redis
        /// </summary>
        /// <param name="key"></param>
        /// <param name="action"></param>
        public void Subscribe(string key, Action<long, string, string> action) => client.Subscribe((key, msg => action(msg.MessageId, msg.Channel, msg.Body)));

        /// <summary>
        /// 获取有序集合的成员数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public long ZCount(string key) => client.ZCard(key);

        /// <summary>
        /// 获取有序集合中指定分数区间的成员数量
        /// </summary>
        /// <param name="key"></param>
        /// <param name="minScore">最小分值</param>
        /// <param name="maxScore">最大分值</param>
        /// <returns></returns>
        public long ZCount(string key, decimal minScore, decimal maxScore) => client.ZCount(key, minScore, maxScore);

        /// <summary>
        /// 移除有序集合中的一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="members"></param>
        /// <returns></returns>
        public bool ZRem(string key, params string[] members) => client.ZRem(key, members) > 0;

        /// <summary>
        /// 向有序集合中添加一个成员
        /// </summary>
        /// <param name="key">缓存KEY</param>
        /// <param name="member">成员值</param>
        /// <param name="score">成员分值</param>
        /// <returns></returns>
        public bool ZSet(string key, string member, decimal score) => client.ZAdd(key, (score, member)) > 0;

        /// <summary>
        ///  移除有序集合中的一个或多个成员
        /// </summary>
        /// <param name="key">缓存KEY</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <returns></returns>
        public bool ZRemByScore(string key, decimal minScore, decimal maxScore) => client.ZRemRangeByScore(key, minScore, maxScore) > 0;

        /// <summary>
        /// 返回有序集合中指定成员的分数
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="merber">成员名称</param>
        /// <returns></returns>
        public decimal? ZScore(string key, string merber) => client.ZScore(key, merber);

        /// <summary>
        /// 有序集合中对指定成员的分数加上增量 increment
        /// </summary>
        /// <param name="key"></param>
        /// <param name="member">成员名称</param>
        /// <param name="increment">递增的数量</param>
        /// <returns></returns>
        public decimal ZIncrBy(string key, string member, decimal increment = 1m) => client.ZIncrBy(key, member, increment);

        /// <summary>
        /// 移除有序集合中给定的分数区间的所有成员
        /// </summary>
        /// <param name="key"></param>
        /// <param name="minScore">最小分值</param>
        /// <param name="maxScore">最大分值</param>
        /// <returns></returns>
        public bool ZRemRangeByScore(string key, decimal minScore, decimal maxScore) => client.ZRemRangeByScore(key, minScore, maxScore) > 0;

        /// <summary>
        /// 获取有序集合的成员列表
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public string[] ZRangeByScore(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => client.ZRangeByScore(key, minScore, maxScore, count, offset);

        /// <summary>
        /// 获取有序集合的成员和分数列表
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public (string member, decimal score)[] ZRangeByScoreWithScores(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => client.ZRangeByScoreWithScores(key, minScore, maxScore, count, offset);

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public T[] ZRevRangeByScore<T>(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => client.ZRevRangeByScore<T>(key, maxScore, minScore, count, offset);

        /// <summary>
        ///  返回有序集中指定分数区间内的成员和分数，分数从高到低排序
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public (string member, decimal score)[] ZRangeByScoreWithScoreList(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => client.ZRevRangeByScoreWithScores(key, maxScore, minScore, count, offset);

        /// <summary>
        ///  向集合添加一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="members"></param>
        /// <returns></returns>
        public long SAdd<T>(string key, params T[] members)
        {
            return client.SAdd(key, members);
        }

        /// <summary>
        ///  返回集合中的所有成员
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string[] SMembers(string key)
        {
            return client.SMembers(key);
        }

        /// <summary>
        ///  返回集合中的所有成员
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T[] SMembers<T>(string key)
        {
            return client.SMembers<T>(key);
        }

        /// <summary>
        ///  获取集合的成员数
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public long SCard(string key)
        {
            return client.SCard(key);
        }

        /// <summary>
        ///  移除集合中一个或多个成员
        /// </summary>
        /// <param name="key"></param>
        /// <param name="members"></param>
        /// <returns></returns>
        public long SRem<T>(string key, params T[] members)
        {

            return client.SRem(key, members);
        }

        /// <summary>
        ///  返回集合中的一个随机元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string SRandMember(string key)
        {
            return client.SRandMember(key);
        }

        /// <summary>
        ///  返回集合中的一个随机元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T SRandMember<T>(string key)
        {
            return client.SRandMember<T>(key);
        }

        /// <summary>
        /// 返回集合中一个或多个随机数的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public string[] SRandMember(string key, int count = 1)
        {
            return client.SRandMembers(key, count);
        }

        /// <summary>
        /// 返回集合中一个或多个随机数的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public T[] SRandMember<T>(string key, int count = 1)
        {
            return client.SRandMembers<T>(key, count);
        }

        /// <summary>
        /// 使用管道模式
        /// </summary>
        /// <returns></returns>
        public CSRedisClientPipe<string> UsePipe()
        {
            var pipe = client.StartPipe();
            return pipe;
        }

        /// <summary>
        /// 执行lua脚本
        /// </summary>
        /// <summary>
        /// 执行lua脚本
        /// </summary>
        public T Eval<T>(string script, string key, params object[] args)
        {
            var sha = client.ScriptLoad(script);
            var response = client.EvalSHA(sha, key, args);
            if (response == null)
            {
                return default;
            }
            else
            {
                var responseStr = response.ToString();
                return responseStr.ToObject<T>();
            }
        }
        #endregion

        #region 异步操作
        /// <summary>
        /// 检查缓存Key是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<bool> ContainsKeyAsync(string key) => await client.ExistsAsync(key);

        /// <summary>
        /// 批量删除缓存Key
        /// </summary>
        /// <param name="key"></param>
        /// <returns>删除成功的记录数量</returns>
        public async Task<bool> DeleteKeyAsync(string key) => await client.DelAsync(key) > 0;

        /// <summary>
        /// 批量删除缓存Key
        /// </summary>
        /// <param name="keys">key列表</param>
        /// <returns>删除成功的记录数量</returns>
        public async Task<bool> DeleteKeyAsync(params string[] keys) => await client.DelAsync(keys) > 0;

        /// <summary>
        /// 重新命名key
        /// </summary>
        /// <param name="key">就的redis key</param>
        /// <param name="newKey">新的redis key</param>
        /// <returns></returns>
        public async Task<bool> RenameKeyAsync(string key, string newKey) => await client.RenameAsync(key, newKey);

        /// <summary>
        /// 设置缓存过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeoutSeconds"></param>
        public async Task<bool> SetExpireAsync(string key, int timeoutSeconds) => await client.ExpireAsync(key, timeoutSeconds);

        /// <summary>
        /// 获取String类型的缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> StringGetAsync(string key) => await client.GetAsync(key);

        /// <summary>
        /// 获取String类型的缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> GetAsync<T>(string key) => await client.GetAsync<T>(key);

        /// <summary>
        /// 获取String类型的缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireSeconds"></param>
        /// <returns></returns>
        public async Task<bool> SetAsync(string key, object value, int expireSeconds = 604800) => await client.SetAsync(key, value, expireSeconds);

        /// <summary>
        /// 获取String类型的缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> StringGetAsync<T>(string key)
        {
            T result = default;
            try
            {
                byte[] btyes = await client.GetAsync<byte[]>(key);
                result = ProtoBufConvert.DeserializeObject<T>(btyes);
            }
            catch (Exception)
            {
                if (result == null && result.IsBaseType())
                {
                    result = await client.GetAsync<T>(key);
                }
            }
            return result;

        }

        /// <summary>
        /// 设置String类型缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireSeconds"></param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync<T>(string key, T value, int expireSeconds = 604800)
        {
            bool isSuccess = false;
            try
            {
                byte[] bytes = ProtoBufConvert.SerializeObject(value);
                isSuccess = await client.SetAsync(key, bytes, expireSeconds);
            }
            catch (Exception)
            {

            }
            return isSuccess;
        }

        /// <summary>
        /// 设置String类型缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireSeconds"></param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync(string key, string value, int expireSeconds = 604800) => await client.SetAsync(key, value, expireSeconds);

        /// <summary>
        /// 原子性递增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <param name="expireSeconds">缓存过期时间(单位：秒)</param>
        /// <returns>增长后的值</returns>
        public async Task<long> StringIncrementAsync(string key, long value = 1, int expireSeconds = 604800)
        {
            var newValue = await client.IncrByAsync(key, value);
            await SetExpireAsync(key, expireSeconds);
            return newValue;
        }

        /// <summary>
        /// 获取hash表的字段数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> GetHashCountAsync(string key) => await client.HLenAsync(key);

        /// <summary>
        /// 检查hash键是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public async Task<bool> ContainsHashKeyAsync(string key, string hashField) => await client.HExistsAsync(key, hashField);

        /// <summary>
        /// 移除hash中的某值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public async Task<bool> DeleteHashAsync(string key, string hashField) => await client.HDelAsync(key, hashField) > 0;

        /// <summary>
        /// 移除hash中的某值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="hashFields"></param>
        /// <returns></returns>
        public async Task<bool> DeleteHashAsync(string key, params string[] hashFields) => await client.HDelAsync(key, hashFields) > 0;

        /// <summary>
        /// 获取Hash值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public async Task<string> HashGetAsync(string key, string hashField) => await client.HGetAsync(key, hashField);

        /// <summary>
        /// 获取Hash值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <returns></returns>
        public async Task<T> HashGetAsync<T>(string key, string hashField)
        {
            T result = default;
            try
            {
                byte[] bytes = await client.HGetAsync<byte[]>(key, hashField);
                result = ProtoBufConvert.DeserializeObject<T>(bytes);
            }
            catch (Exception)
            {
                if (result == null && result.IsBaseType())
                {
                    result = await client.HGetAsync<T>(key, hashField);
                }
            }
            return result;
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public async Task<bool> HashSetAsync(string key, string hashField, string value, int timeoutSeconds = 604800)
        {
            return await EvalAsync<bool>(LuaScriptConstant.HsetExpireScript, key, hashField, value, timeoutSeconds);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <param name="value"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public async Task<bool> HashSetAsync<T>(string key, string hashField, T value, int timeoutSeconds = 604800) where T : class
        {
            byte[] bytes = ProtoBufConvert.SerializeObject(value);
            return await EvalAsync<bool>(LuaScriptConstant.HsetExpireScript, key, hashField, bytes, timeoutSeconds);
        }

        /// <summary>
        /// 原子性递增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashField"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <param name="timeoutSeconds">缓存过期时间（单位：秒）</param>
        /// <returns>增长后的值</returns>
        public async Task<long> HashIncrementAsync(string key, string hashField, long value = 1, int timeoutSeconds = 604800)
        {
            long increment = 0;
            try
            {
                bool keyExists = await ContainsKeyAsync(key);//缓存是否存在
                increment = await client.HIncrByAsync(key, hashField, value);
                if (!keyExists)
                {
                    await SetExpireAsync(key, timeoutSeconds);
                }
            }
            catch
            {
            }
            return increment;
        }

        /// <summary>
        /// 原子性递增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <returns>增长后的值</returns>
        public async Task<long> StringIncrementNoExpireAsync(string key, long value = 1)
        {
            return await client.IncrByAsync(key, value);
        }

        /// <summary>
        /// 原子性递增 绝对过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value">增量：可以为负数</param>
        /// <param name="expireSeconds">过期时间</param>
        /// <returns>增长后的值</returns>
        public async Task<long> StringIncrementByAbsoluteExpireAsync(string key, long value = 1, int expireSeconds = 604800)
        {
            var newValue = await client.IncrByAsync(key, value);
            if (newValue == value)
            {
                SetExpire(key, expireSeconds);
            }
            return newValue;
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public async Task<bool> SetNxAsync(string key, object value, int timeoutSeconds)
        {
            bool isSuccess = false;
            try
            {
                return await EvalAsync<bool>(LuaScriptConstant.SetNxScript, key, value, timeoutSeconds);
            }
            catch (Exception)
            {
                await DeleteKeyAsync(key);
            }
            return isSuccess;
        }

        /// <summary>
        /// 分布式锁
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeoutSeconds"></param>
        /// <returns></returns>
        public async Task<CSRedisClientLockNx> LockNxAsync(string key, int timeoutSeconds = 5)
        {
            CSRedisClientLockNx lockClient = null;
            try
            {
                bool isSuccess = await SetNxAsync(key, 1, timeoutSeconds);
                if (isSuccess)
                {
                    //创建客户端
                    lockClient = new CSRedisClientLockNx(key, client);
                }
            }
            catch (Exception)
            {
                await DeleteKeyAsync(key);
            }
            return lockClient;
        }

        /// <summary>
        /// 消息发布
        /// </summary>
        /// <param name="channel">频道名</param>
        /// <param name="message">消息内容</param>
        /// <returns></returns>
        public async Task<long> PublishNoneMessageIdAsync(string channel, string message)
        {
            return await client.PublishNoneMessageIdAsync(channel, message);
        }

        /// <summary>
        /// 将一个或多个值插入到列表头部
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value">一个或多个值</param>
        /// <returns>执行 LPUSH 命令后，列表的长度</returns>
        public async Task<long> LPushAsync<T>(string key, params T[] value) where T : class
        {
            return await client.LPushAsync(key, value);
        }

        /// <summary>
        /// 从列表中移除等于当前值的所有元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<long> LRemAsync<T>(string key, T value) where T : class
        {
            return await client.LRemAsync(key, 0, value);
        }

        /// <summary>
        /// 从列表中移除等于当前值的所有元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">当前key</param>
        /// <param name="value">当前值</param>
        /// <returns></returns>
        public long LRem<T>(string key, T value) where T : class
        {
            return client.LRem(key, 0, value);
        }

        /// <summary>
        /// 对一个列表进行修剪，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="start"> 开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public async Task<bool> LTrimAsync<T>(string key, long start, long stop) where T : class
        {
            return await client.LTrimAsync(key, start, stop);
        }

        /// <summary>
        /// 获取有序集合的成员数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> ZCountAsync(string key) => await client.ZCardAsync(key);

        /// <summary>
        /// 获取有序集合中指定分数区间的成员数量
        /// </summary>
        /// <param name="key"></param>
        /// <param name="minScore">最小分值</param>
        /// <param name="maxScore">最大分值</param>
        /// <returns></returns>
        public async Task<long> ZCountAsync(string key, decimal minScore, decimal maxScore) => await client.ZCountAsync(key, minScore, maxScore);

        /// <summary>
        /// 移除有序集合中的一个或多个成员
        /// </summary>
        /// <param name="key"></param>
        /// <param name="members"></param>
        /// <returns></returns>
        public async Task<bool> ZRemAsync(string key, params string[] members) => (await client.ZRemAsync(key, members)) > 0;

        /// <summary>
        /// 返回有序集合中指定成员的分数
        /// </summary>
        /// <param name="key">KEY</param>
        /// <param name="merber">成员名称</param>
        /// <returns></returns>
        public async Task<decimal?> ZScoreAsync(string key, string merber) => await client.ZScoreAsync(key, merber);

        /// <summary>
        /// 有序集合中对指定成员的分数加上增量 increment
        /// </summary>
        /// <param name="key"></param>
        /// <param name="member">成员名称</param>
        /// <param name="increment">递增的数量</param>
        /// <returns></returns>
        public async Task<decimal> ZIncrByAsync(string key, string member, decimal increment = 1m) => await client.ZIncrByAsync(key, member, increment);

        /// <summary>
        /// 移除有序集合中给定的分数区间的所有成员
        /// </summary>
        /// <param name="key"></param>
        /// <param name="minScore">最小分值</param>
        /// <param name="maxScore">最大分值</param>
        /// <returns></returns>
        public async Task<bool> ZRemRangeByScoreAsync(string key, decimal minScore, decimal maxScore) => (await client.ZRemRangeByScoreAsync(key, minScore, maxScore)) > 0;

        /// <summary>
        ///  移除有序集合中的一个或多个成员
        /// </summary>
        /// <param name="key">缓存KEY</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <returns></returns>
        public async Task<bool> ZRemByScoreAsync(string key, decimal minScore, decimal maxScore) => (await client.ZRemRangeByScoreAsync(key, minScore, maxScore)) > 0;

        /// <summary>
        /// 向有序集合中添加一个成员
        /// </summary>
        /// <param name="key">缓存KEY</param>
        /// <param name="member">成员值</param>
        /// <param name="score">成员分值</param>
        /// <returns></returns>
        public async Task<bool> ZSetAsync(string key, string member, decimal score) => (await client.ZAddAsync(key, (score, member))) > 0;

        /// <summary>
        /// 获取有序集合的成员列表
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public async Task<string[]> ZRangeByScoreAsync(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => await client.ZRangeByScoreAsync(key, minScore, maxScore, count, offset);

        /// <summary>
        /// 获取有序集合的成员列表
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public async Task<T[]> ZRangeByScoreAsync<T>(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => await client.ZRangeByScoreAsync<T>(key, minScore, maxScore, count, offset);

        /// <summary>
        /// 获取有序集合的成员和分数列表
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public async Task<(string member, decimal score)[]> ZRangeByScoreWithScoresAsync(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => await client.ZRangeByScoreWithScoresAsync(key, minScore, maxScore, count, offset);

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public async Task<string[]> ZRevRangeByScoreAsync(string key, decimal minScore, decimal maxScore, long? count = null, long? offset = 0) => await client.ZRevRangeByScoreAsync(key, maxScore, minScore, count, offset);

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public async Task<T[]> ZRevRangeByScoreAsync<T>(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => await client.ZRevRangeByScoreAsync<T>(key, maxScore, minScore, count, offset);

        /// <summary>
        ///  返回有序集中指定分数区间内的成员和分数，分数从高到低排序
        /// </summary>
        /// <param name="key">缓存KEY(不含prefix前辍)</param>
        /// <param name="minScore">分数最小值</param>
        /// <param name="maxScore">分数最大值</param>
        /// <param name="count">返回的成员数量</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public async Task<(string member, decimal score)[]> ZRangeByScoreWithScoreListAsync(string key, decimal minScore, decimal maxScore, long? count = null, long offset = 0) => await client.ZRevRangeByScoreWithScoresAsync(key, maxScore, minScore, count, offset);

        /// <summary>
        /// 移出并获取列表的第一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> LPopAsync(string key)
        {
            return await client.LPopAsync(key);
        }

        /// <summary>
        /// 移出并获取列表的第一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> LPopAsync<T>(string key) where T : class
        {
            return await client.LPopAsync<T>(key);
        }

        /// <summary>
        /// 移出并获取列表的最后一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> RPopAsync(string key)
        {
            return await client.RPopAsync(key);
        }

        /// <summary>
        /// 移出并获取列表的最后一个元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> RPopAsync<T>(string key) where T : class
        {
            return await client.RPopAsync<T>(key);
        }

        /// <summary>
        /// 获取列表长度
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> LLenAsync(string key)
        {
            return await client.LLenAsync(key);
        }

        /// <summary>
        /// 获取列表指定范围内的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop"> 结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public async Task<string[]> LRangeAsync(string key, long start, long stop)
        {
            return await client.LRangeAsync(key, start, stop);
        }

        /// <summary>
        /// 获取列表指定范围内的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop"> 结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public async Task<T[]> LRangeAsync<T>(string key, long start, long stop) where T : class
        {
            return await client.LRangeAsync<T>(key, start, stop);
        }

        /// <summary>
        ///  向集合添加一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="members"></param>
        /// <returns></returns>
        public async Task<long> SAddAsync<T>(string key, params T[] members)
        {
            return await client.SAddAsync(key, members);
        }

        /// <summary>
        ///  返回集合中的所有成员
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string[]> SMembersAsync(string key)
        {
            return await client.SMembersAsync(key);
        }

        /// <summary>
        ///  返回集合中的所有成员
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T[]> SMembersAsync<T>(string key)
        {
            return await client.SMembersAsync<T>(key);
        }

        /// <summary>
        ///  获取集合的成员数
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> SCardAsync<T>(string key)
        {
            return await client.SCardAsync(key);
        }

        /// <summary>
        /// 移除集合中一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="members"></param>
        /// <returns></returns>
        public async Task<long> SRemAsync<T>(string key, params T[] members)
        {
            return await client.SRemAsync(key, members);
        }

        /// <summary>
        ///  返回集合中的一个随机元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> SRandMemberAsync(string key)
        {
            return await client.SRandMemberAsync(key);
        }

        /// <summary>
        ///  返回集合中的一个随机元素
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> SRandMemberAsync<T>(string key)
        {
            return await client.SRandMemberAsync<T>(key);
        }

        /// <summary>
        /// 返回集合中一个或多个随机数的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public async Task<string[]> SRandMemberAsync(string key, int count = 1)
        {
            return await client.SRandMembersAsync(key, count);
        }

        /// <summary>
        /// 返回集合中一个或多个随机数的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public async Task<T[]> SRandMemberAsync<T>(string key, int count = 1)
        {
            return await client.SRandMembersAsync<T>(key, count);
        }

        /// <summary>
        /// 获取Hash所有键和值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<Dictionary<string, string>> HashGetAllAsync(string key) => await client.HGetAllAsync(key);

        /// <summary>
        /// 获取存储在哈希表中多个字段的值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public async Task<string[]> HashGetMultipleAsync(string key, params string[] fields) => await client.HMGetAsync(key, fields);

        /// <summary>
        /// 设置哈希表- 同时将多个 field-value (域-值)对设置到哈希表 key 中
        /// </summary>
        /// <param name="key"></param>
        /// <param name="keyValues"> key1 value1 [key2 value2]</param>
        /// <returns></returns>
        public async Task<bool> HashSetMultipleAsync(string key, params object[] keyValues) => await client.HMSetAsync(key, keyValues);

        /// <summary>
        /// 执行lua脚本
        /// </summary>
        public async Task<T> EvalAsync<T>(string script, string key, params object[] args)
        {
            var sha = await client.ScriptLoadAsync(script);
            var response = await client.EvalSHAAsync(sha, key, args);
            if (response == null)
            {
                return default;
            }
            else
            {
                var responseStr = response.ToString();
                return responseStr.ToObject<T>();
            }
        }
        #endregion
    }
}